home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
351-375
/
351
/
pdc
/
pdcsrc.lzh
/
PDC
/
Analyze.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-06
|
17KB
|
738 lines
/* PDC Compiler - A Freely Distributable C Compiler for the Amiga
* Based upon prior work by Matthew Brandt and Jeff Lydiatt.
*
* PDC Compiler release 3.3 Copyright (C) 1989 Paul Petersen and Lionel Hummel.
* PDC Software Distribution (C) 1989 Lionel Hummel and Paul Petersen.
*
* This code is freely redistributable upon the conditions that this
* notice remains intact and that modified versions of this file not be
* distributed as part of the PDC Software Distribution without the express
* consent of the copyright holders.
*
*------------------------------------------------------------------
*
* $Log: Analyze.c,v $
* Revision 3.33 90/04/04 02:25:11 lionel
* Added unsigned multiply, divide, and modulo expression handling.
*
* Revision 3.32 90/02/03 16:22:48 lionel
* None
*
*------------------------------------------------------------------
*/
/*
* Analyze.c
*
* This module will step through the parse tree and find all optimizable
* expressions. at present these expressions are limited to expressions that
* are valid throughout the scope of the function. the list of optimizable
* expressions is:
*
* Constants, global and static addresses, auto addresses, contents of auto
* addresses.
*
* Contents of auto addresses are valid only if the address is never referred to
* without dereferencing.
*
* Scan will build a list of optimizable expressions which opt1 will replace
* during the second optimization pass.
*/
#include <stdio.h>
#include "C.h"
#include "Expr.h"
#include "Gen.h"
#include "Cglbdec.h"
#include <stab.h>
extern struct amode push[], pop[];
extern struct amode *gen_expr(), *makedreg(), *makeareg(), *make_mask();
#ifdef GENERATE_DBX
extern char *dbx_addreg();
#endif
extern char *xalloc();
static struct cse *olist; /* list of optimizable expressions */
int
equalnode(node1, node2)
/*
* equalnode will return 1 if the expressions pointed to by node1 and node2
* are equivalent.
*/
register struct enode *node1, *node2;
{
if (node1 == NULL || node2 == NULL)
return FALSE;
if (node1->nodetype != node2->nodetype)
return FALSE;
if (node1->v.i == node2->v.i) {
if (node1->nodetype == en_icon || node1->nodetype == en_labcon ||
node1->nodetype == en_nacon || node1->nodetype == en_autocon)
return TRUE;
}
if (lvalue(node1) && equalnode(node1->v.p[0], node2->v.p[0]))
return TRUE;
return FALSE;
}
struct cse *
searchnode(node)
/*
* searchnode will search the common expression table for an entry that
* matches the node passed and return a pointer to it.
*/
register struct enode *node;
{
register struct cse *csp;
for (csp = olist; csp != NULL; csp = csp->next)
if (equalnode(node, csp->exp))
return csp;
return NULL;
}
struct enode *
copynode(node)
/*
* copy the node passed into a new enode so it wont get corrupted during
* substitution.
*/
struct enode *node;
{
struct enode *temp;
if (node == NULL)
return NULL;
temp = (struct enode *) xalloc(sizeof(struct enode));
temp->nodetype = node->nodetype;
temp->v.p[0] = node->v.p[0];
temp->v.p[1] = node->v.p[1];
return temp;
}
struct cse *
enternode(node, duse)
/*
* enternode will enter a reference to an expression node into the common
* expression table. duse is a flag indicating whether or not this reference
* will be dereferenced.
*/
struct enode *node;
int duse;
{
struct cse *csp;
if ((csp = searchnode(node)) == NULL) { /* add to tree */
csp = (struct cse *) xalloc(sizeof(struct cse));
csp->next = olist;
csp->uses = 1;
csp->duses = (duse != 0);
csp->exp = copynode(node);
csp->voidf = FALSE;
olist = csp;
return csp;
}
++(csp->uses);
if (duse)
++(csp->duses);
return csp;
}
struct cse *
voidauto(node)
/*
* voidauto will void an auto dereference node which points to the same auto
* constant as node.
*/
struct enode *node;
{
struct cse *csp;
csp = olist;
while (csp != NULL) {
if (lvalue(csp->exp) && equalnode(node, csp->exp->v.p[0])) {
if (csp->voidf)
return NULL;
csp->voidf = TRUE;
return csp;
}
csp = csp->next;
}
return NULL;
}
void
scanexpr(node, duse)
/*
* scanexpr will scan the expression pointed to by node for optimizable
* subexpressions. when an optimizable expression is found it is entered into
* the tree. if a reference to an autocon node is scanned the corresponding
* auto dereferenced node will be voided. duse should be set if the
* expression will be dereferenced.
*/
struct enode *node;
{
struct cse *csp, *csp1;
if (node == NULL)
return;
switch (node->nodetype) {
case en_icon:
case en_labcon:
case en_nacon:
enternode(node, duse);
break;
case en_autocon:
if ((csp = voidauto(node)) != NULL) {
csp1 = enternode(node, duse);
csp1->uses = (csp1->duses += csp->uses);
}
else
csp1 = enternode(node, duse);
csp1->voidf = TRUE;
break;
case en_b_ref:
case en_ub_ref:
case en_w_ref:
case en_uw_ref:
case en_l_ref:
case en_ul_ref:
if (node->v.p[0]->nodetype == en_autocon) {
csp = enternode(node, 1);
csp1 = searchnode(node->v.p[0]);
if (csp1 != NULL && csp1->voidf)
csp1 = voidauto(node->v.p[0]);
}
else
scanexpr(node->v.p[0], 1);
break;
case en_cbl:
case en_cbw:
case en_cwl:
case en_clf:
case en_cld:
case en_cfd:
case en_cfl:
case en_cdl:
case en_cdf:
case en_uminus:
case en_compl:
case en_not:
case en_info:
scanexpr(node->v.p[0], duse);
break;
case en_ainc:
case en_adec:
case en_faincs:
case en_fadecs:
case en_faincd:
case en_fadecd:
scanexpr(node->v.p[0], 0);
scanexpr(node->v.p[1], 0);
break;
case en_asadd:
case en_assub:
case en_add:
case en_sub:
case en_mul:
case en_umul:
case en_div:
case en_udiv:
case en_lsh:
case en_rsh:
case en_mod:
case en_umod:
case en_and:
case en_or:
case en_xor:
case en_lor:
case en_land:
case en_eq:
case en_ne:
case en_gt:
case en_ugt:
case en_ge:
case en_uge:
case en_lt:
case en_ult:
case en_le:
case en_ule:
case en_asmul:
case en_asdiv:
case en_asmod:
case en_asumul:
case en_asudiv:
case en_asumod:
case en_aslsh:
case en_asrsh:
case en_asand:
case en_asor:
case en_aseor:
case en_cond:
case en_void:
case en_assign:
scanexpr(node->v.p[0], 0);
scanexpr(node->v.p[1], 0);
break;
case en_fcall:
if (node->v.p[0]->nodetype == en_nacon) {
if (strncmp(node->v.p[0]->v.sp, "__BUILTIN_", 10) == 0) {
scanexpr(node->v.p[1], 0);
return;
}
if (strncmp(node->v.p[0]->v.sp, "__LIBCALL_", 10) == 0) {
scanexpr(node->v.p[1], 0);
return;
}
}
scanexpr(node->v.p[0], 1);
scanexpr(node->v.p[1], 0);
break;
case en_fnegs:
case en_fadds:
case en_fsubs:
case en_fmuls:
case en_fdivs:
case en_fmods:
case en_fnegd:
case en_faddd:
case en_fsubd:
case en_fmuld:
case en_fdivd:
case en_fmodd:
case en_d_ref:
case en_f_ref:
case en_m_ref:
break;
}
}
void
scan(block)
/*
* scan will gather all optimizable expressions into the expression list for
* a block of statements.
*/
struct snode *block;
{
while (block != NULL) {
switch (block->stype) {
case st_return:
case st_expr:
opt4(&block->exp);
scanexpr(block->exp, 0);
break;
case st_while:
case st_do:
opt4(&block->exp);
scanexpr(block->exp, 0);
scan(block->s1);
break;
case st_for:
opt4(&block->label);
scanexpr(block->label, 0);
opt4(&block->exp);
scanexpr(block->exp, 0);
scan(block->s1);
opt4(&block->s2);
scanexpr(block->s2, 0);
break;
case st_if:
opt4(&block->exp);
scanexpr(block->exp, 0);
scan(block->s1);
scan(block->s2);
break;
case st_switch:
opt4(&block->exp);
scanexpr(block->exp, 0);
scan(block->s1);
break;
case st_case:
scan(block->s1);
break;
case st_goto:
case st_label:
case st_break:
case st_continue:
case st_comment:
break;
}
block = block->next;
}
}
void
exchange(c1)
/*
* exchange will exchange the order of two expression entries following c1 in
* the linked list.
*/
struct cse **c1;
{
struct cse *csp1, *csp2;
csp1 = *c1;
csp2 = csp1->next;
csp1->next = csp2->next;
csp2->next = csp1;
*c1 = csp2;
}
int
desire(csp)
/*
* returns the desirability of optimization for a subexpression.
*/
struct cse *csp;
{
struct enode *ep1;
if (csp->voidf)
return 0;
ep1 = csp->exp;
if (ep1->nodetype == en_icon && ep1->v.i < 16 && ep1->v.i >= 0)
return (0);
if (lvalue(csp->exp))
return 2 * csp->uses;
return csp->uses;
}
int
bsort(list)
/*
* bsort implements a bubble sort on the expression list.
*/
struct cse **list;
{
int rc;
struct cse *csp1, *csp2;
csp1 = *list;
if (csp1 == NULL || csp1->next == NULL)
return 0;
rc = bsort(&(csp1->next));
csp2 = csp1->next;
if (desire(csp1) < desire(csp2)) {
exchange(list);
return 1;
}
return rc;
}
void
allocate()
/*
* allocate will allocate registers for the expressions that have a high
* enough desirability.
*/
{
struct cse *csp;
struct enode *exptr;
int datareg, addreg, mask;
struct amode *ap, *ap2;
datareg = 3;
addreg = 10;
mask = 0;
while (bsort(&olist)); /* sort the expression list */
for (csp = olist; csp != NULL; csp = csp->next) {
csp->reg = -1;
if (desire(csp) >= 3) {
if (csp->duses > (csp->uses / 5)) {
if (lvalue(csp->exp) && datareg < 8)
csp->reg = datareg++;
else if (addreg < 8 + Options.Frame)
csp->reg = addreg++;
else if (datareg < 8)
csp->reg = datareg++;
}
}
if (csp->reg != -1)
mask = mask | (1 << csp->reg);
}
if (mask != 0)
gen_code(op_movem, 4, make_mask(mask), push);
save_mask = mask;
for (csp = olist; csp != NULL; csp = csp->next) {
if (csp->reg != -1) { /* see if preload needed */
exptr = csp->exp;
if (!lvalue(exptr) || (exptr->v.p[0]->v.i > 0)) {
initstack();
ap = gen_expr(exptr, F_ALL, 4);
if (csp->reg < 8) {
ap2 = makedreg((enum e_am) (csp->reg));
if (ap->mode == am_immed)
make_legal(ap, F_AREG, 4);
gen_code(op_move, 4, ap, ap2);
}
else {
ap2 = makeareg((enum e_am) (csp->reg - 8));
gen_code(op_move, 4, ap, ap2);
}
freeop(ap);
}
}
}
}
void
repexpr(node)
/*
* repexpr will replace all allocated references within an expression with
* tempref nodes.
*/
struct enode *node;
{
struct cse *csp;
if (node == NULL)
return;
switch (node->nodetype) {
case en_icon:
case en_nacon:
case en_labcon:
case en_autocon:
if ((csp = searchnode(node)) != NULL)
if (csp->reg > 0) {
node->nodetype = en_tempref;
node->v.i = csp->reg;
}
break;
case en_stabs:
case en_stabn:
if (node->v.dp != NULL && node->v.dp->ref != NULL) {
if ((csp = searchnode(node->v.dp->ref)) != NULL) {
if (csp->reg > 0) {
node->v.dp->tag = N_RSYM;
#ifdef GENERATE_DBX
node->v.dp->sp = dbx_addreg(node->v.dp->sp);
#endif
node->v.dp->ref->nodetype = en_tempref;
node->v.dp->ref->v.i = csp->reg;
}
}
}
break;
case en_b_ref:
case en_ub_ref:
case en_w_ref:
case en_uw_ref:
case en_l_ref:
case en_ul_ref:
case en_m_ref:
case en_f_ref:
case en_d_ref:
if ((csp = searchnode(node)) != NULL) {
if (csp->reg > 0) {
node->nodetype = en_tempref;
node->v.i = csp->reg;
}
else
repexpr(node->v.p[0]);
}
else
repexpr(node->v.p[0]);
break;
case en_cbl:
case en_cbw:
case en_cwl:
case en_clf:
case en_cld:
case en_cfd:
case en_cfl:
case en_cdl:
case en_cdf:
case en_uminus:
case en_not:
case en_compl:
case en_info:
repexpr(node->v.p[0]);
break;
case en_ainc:
case en_adec:
case en_faincs:
case en_fadecs:
case en_faincd:
case en_fadecd:
repexpr(node->v.p[0]);
repexpr(node->v.p[1]);
break;
case en_fnegs:
case en_fnegd:
repexpr(node->v.p[0]);
break;
case en_add:
case en_sub:
case en_mul:
case en_umul:
case en_div:
case en_udiv:
case en_mod:
case en_umod:
case en_lsh:
case en_rsh:
case en_and:
case en_or:
case en_xor:
case en_land:
case en_lor:
case en_eq:
case en_ne:
case en_lt:
case en_ult:
case en_le:
case en_ule:
case en_gt:
case en_ugt:
case en_ge:
case en_uge:
case en_cond:
case en_void:
case en_asadd:
case en_assub:
case en_asmul:
case en_asdiv:
case en_asmod:
case en_asumul:
case en_asudiv:
case en_asumod:
case en_asor:
case en_asand:
case en_aslsh:
case en_asrsh:
case en_aseor:
case en_fcall:
case en_assign:
case en_fadds:
case en_fsubs:
case en_fmuls:
case en_fdivs:
case en_fmods:
case en_faddd:
case en_fsubd:
case en_fmuld:
case en_fdivd:
case en_fmodd:
repexpr(node->v.p[0]);
repexpr(node->v.p[1]);
break;
}
}
void
repcse(block)
/*
* repcse will scan through a block of statements replacing the optimized
* expressions with their temporary references.
*/
struct snode *block;
{
while (block != NULL) {
switch (block->stype) {
case st_stabn:
case st_stabs:
repexpr(block->exp);
break;
case st_return:
case st_expr:
repexpr(block->exp);
break;
case st_while:
case st_do:
repexpr(block->exp);
repcse(block->s1);
break;
case st_for:
repexpr(block->label);
repexpr(block->exp);
repcse(block->s1);
repexpr(block->s2);
break;
case st_if:
repexpr(block->exp);
repcse(block->s1);
repcse(block->s2);
break;
case st_switch:
repexpr(block->exp);
repcse(block->s1);
break;
case st_case:
repcse(block->s1);
break;
case st_goto:
case st_label:
case st_break:
case st_continue:
case st_comment:
break;
}
block = block->next;
}
}
void
opt1(block)
/*
* opt1 is the externally callable optimization routine. it will collect and
* allocate common subexpressions and substitute the tempref for all
* occurrances of the expression within the block.
*
*/
struct snode *block;
{
if (Options.Optimize) {
olist = NULL;
scan(block); /* collect expressions */
allocate(); /* allocate registers */
repcse(block); /* replace allocated expressions */
}
}